package metric;

import java.util.HashMap;
import java.util.Observable;
import java.util.Vector;

import simulationEngine.SimulationEngine;

import databaseConnect.SimulationExecutionWriteProcessor;
import datatypes.BluetoothDeviceAddress;
import datatypes.Host;
import datatypes.Message;
import datatypes.MetricObject;
import datatypes.MetricObjectType;

public class CentralObservableUnit extends Observable {
	
	private int uniqueSimID = -1;
	private static int simIDinDB = -1;
	
	//BEGIN "SINGLETON"
	private static HashMap <Integer, CentralObservableUnit> instanceMap = null;

	private CentralObservableUnit (int UniqueSimID){
		this.uniqueSimID = UniqueSimID;
		this.addObserver(CentralObserver.getInstance(UniqueSimID));
	}

	private static CentralObservableUnit getInstance(int simulationID){
		if (instanceMap == null){
			instanceMap = new HashMap<Integer, CentralObservableUnit>();
		}
		if (instanceMap.get(simulationID)== null){
			simIDinDB = SimulationEngine.getEngine(simulationID).getSimulationIDinDB();
			instanceMap.put(Integer.valueOf(simulationID), new CentralObservableUnit(SimulationExecutionWriteProcessor.setUUID(simIDinDB)));
		}
		return instanceMap.get(simulationID);
	}
	//END "SINGLETON"
	
	public static void clear(){
		instanceMap = null;
	}
	
	//Helping Methods
	//Methods for inform Observer that something happened
	private void informObserver(MetricObject obj){
		this.setChanged();
		this.notifyObservers(obj);
	}
	
	public void simulationStarted (int SimulationEngineID, int SimulationIDinDB){
		/*
		 * 1. UniqueSimulationID
		 * 2. SimulationIDinDB
		 */
		Vector<String> tmp = new Vector<String>();
		this.simIDinDB = SimulationIDinDB;
		tmp.add(this.uniqueSimID + "");
		tmp.add(this.simIDinDB + "");
		getInstance(SimulationEngineID).informObserver(new MetricObject(MetricObjectType.META_MSG, tmp, "SimulationStarted", null));
	}
	
	public static void scenarioStarted (int SimulationID, int ScenarioID){
		/*
		 * 1. SimulationID
		 * 2. ScenarioID
		 */
		Vector<String> tmp = new Vector<String>();
		tmp.add(SimulationID + "");
		tmp.add(ScenarioID + "");
		getInstance(SimulationID).informObserver(new MetricObject(MetricObjectType.META_MSG, tmp, "ScenarioStarted" , null));
	}
	
	public static void discoveryServiceEnabled(Host host, int timestepID){
		/*
		 * 1. SimulationID
		 * 2. ScenarioID
		 * 3. HostID
		 * 4. TimestampID
		 * 
		 */
		Vector<String> tmp = new Vector<String>();
		tmp.add(host.getSimulationID() + "");
		tmp.add(host.getScenarioID() + "");
		tmp.add(host.getID() + "");
		tmp.add(timestepID + "");
		getInstance(host.getSimulationID()).informObserver(new MetricObject(MetricObjectType.DISCOVERY_MSG, tmp, "ServiceEnabled", timestepID, host.getDiscoveryMechanism()));
	}
	
	public static void discoveryServiceDisabled(Host host, int timeStepID){
		/*
		 * 1. SimulationID
		 * 2. ScenarioID
		 * 3. HostID
		 * 4. TimestampID
		 * 
		 */
		Vector<String> tmp = new Vector<String>();
		tmp.add(host.getSimulationID() + "");
		tmp.add(host.getScenarioID() + "");
		tmp.add(host.getID() + "");
		tmp.add(timeStepID + "");
		getInstance(host.getSimulationID()).informObserver(new MetricObject(MetricObjectType.DISCOVERY_MSG, tmp, "ServiceDisabled", timeStepID, host.getDiscoveryMechanism()));		
	}
	
	public static void discoveryServiceSendMessage (Host sender, String receiver, Message msg, int timeStepID){
		/*
		 * 1. SimulationID
		 * 2. ScenarioID
		 * 3. HostID (Sender)
		 * 4. HostID (Receiver)
		 * 5. MessageID
		 * 6. TimestepID
		 * 
		 */
		Vector<String> tmp = new Vector<String>();
		tmp.add(sender.getSimulationID() + "");
		tmp.add(sender.getScenarioID() + "");
		tmp.add(sender.getID() + "");
		tmp.add(receiver);
		tmp.add(msg.getMsgID() + "");
		tmp.add(timeStepID + "");
		getInstance(sender.getSimulationID()).informObserver(new MetricObject(MetricObjectType.DISCOVERY_MSG, tmp, "SendMessage", timeStepID, sender.getDiscoveryMechanism()));			
	}
	
	public static void discoveryServiceReceiveMessage (Host receiver, String sender, Message msg, int timeStepID){
		/*
		 * 1. SimulationID
		 * 2. ScenarioID
		 * 3. HostID (Sender)
		 * 4. HostID (Receiver)
		 * 5. MessageID
		 * 6. TimestepID
		 * 
		 */
		Vector<String> tmp = new Vector<String>();
		tmp.add(receiver.getSimulationID() + "");
		tmp.add(receiver.getScenarioID() + "");
		tmp.add(receiver.getID() + "");
		tmp.add(sender);
		tmp.add(msg.getMsgID() + "");
		tmp.add(timeStepID + "");
		getInstance(receiver.getSimulationID()).informObserver(new MetricObject(MetricObjectType.DISCOVERY_MSG, tmp, "ReceiveMessage", timeStepID, receiver.getDiscoveryMechanism()));			
	}
	
	public static void routingRemoteHostConnected (Host server, BluetoothDeviceAddress client, int timeStepID){
		/*
		 * 1. SimulationID
		 * 2. ScenarioID
		 * 3. HostID (Server)
		 * 4. HostID (Client)
		 * 5. TimestepID
		 * 
		 */
		Vector<String> tmp = new Vector<String>();
		tmp.add(server.getSimulationID() + "");
		tmp.add(server.getScenarioID() + "");
		tmp.add(server.getID() + "");
		tmp.add(client.getFirstPart());
		tmp.add(timeStepID + "");
		getInstance(server.getSimulationID()).informObserver(new MetricObject(MetricObjectType.ROUTING_MSG, tmp, "RemoteHostConnected", timeStepID, server.getDiscoveryMechanism()));			
	}

	public static void disableBluetoothDevice(Host host, int timeStepID) {
		/*
		 * 1. SimulationID
		 * 2. ScenarioID
		 * 3. HostID (Disabled Host)
		 * 4. TimestepID
		 * 
		 */
		Vector<String> tmp = new Vector<String>();
		tmp.add(host.getSimulationID() + "");
		tmp.add(host.getScenarioID() + "");
		tmp.add(host.getID() + "");
		tmp.add(timeStepID + "");
		getInstance(host.getSimulationID()).informObserver(new MetricObject(MetricObjectType.META_MSG, tmp, "DeviceDisabled", timeStepID, host.getDiscoveryMechanism()));			
	}

	public static void enableBluetoothDevice(Host host, int timeStepID) {
		/*
		 * 1. SimulationID
		 * 2. ScenarioID
		 * 3. HostID (Enabled Host)
		 * 4. TimestepID
		 * 
		 */
		Vector<String> tmp = new Vector<String>();
		tmp.add(host.getSimulationID() + "");
		tmp.add(host.getScenarioID() + "");
		tmp.add(host.getID() + "");
		tmp.add(timeStepID + "");
		getInstance(host.getSimulationID()).informObserver(new MetricObject(MetricObjectType.META_MSG, tmp, "DeviceEnabled", timeStepID, host.getDiscoveryMechanism()));			
	}

	public static void logError(Host host, int timeStepID, String cause) {
		/*
		 * 1. SimulationID
		 * 2. ScenarioID
		 * 3. HostID (Host where the error Occured)
		 * 4. Errorcause
		 * 5. TimestepID
		 * 
		 */
		Vector<String> tmp = new Vector<String>();
		tmp.add(host.getSimulationID() + "");
		tmp.add(host.getScenarioID() + "");
		tmp.add(host.getID() + "");
		tmp.add(cause);
		tmp.add(timeStepID + "");
		getInstance(host.getSimulationID()).informObserver(new MetricObject(MetricObjectType.META_MSG, tmp, "Error", timeStepID, host.getDiscoveryMechanism()));					
	}

	public static void networkAckSignalInvoked(Host host, BluetoothDeviceAddress target,int timeStepID,
			Message msg) {
		/*
		 * 1. SimulationID
		 * 2. ScenarioID
		 * 3. HostID (Sender)
		 * 4. HostID (Receiver)
		 * 5. MessageID
		 * 6. TimestepID
		 * 
		 */
		Vector<String> tmp = new Vector<String>();
		tmp.add(host.getSimulationID() + "");
		tmp.add(host.getScenarioID() + "");
		tmp.add(host.getID() + "");
		tmp.add(target.getFirstPart());
		tmp.add(msg.getMsgID() + "");
		tmp.add(timeStepID + "");
		getInstance(host.getSimulationID()).informObserver(new MetricObject(MetricObjectType.ROUTING_MSG, tmp, "ACKinvoked", timeStepID, host.getDiscoveryMechanism()));			
	}

	public static void networkMessageReceived(Host host, int timeStepID,
			Message msg, BluetoothDeviceAddress source) {
		/*
		 * 1. SimulationID
		 * 2. ScenarioID
		 * 3. HostID (Receiver)
		 * 4. HostID (Sender = Source)
		 * 5. MessageID
		 * 6. TimestepID
		 * 
		 */
		Vector<String> tmp = new Vector<String>();
		tmp.add(host.getSimulationID() + "");
		tmp.add(host.getScenarioID() + "");
		tmp.add(host.getID() + "");
		tmp.add(source.getFirstPart());
		tmp.add(msg.getMsgID() + "");
		tmp.add(timeStepID + "");
		getInstance(host.getSimulationID()).informObserver(new MetricObject(MetricObjectType.ROUTING_MSG, tmp, "ReceiveMessage", timeStepID, host.getDiscoveryMechanism()));			
	}

	public static void networkMessageLost(Host host,
			BluetoothDeviceAddress target, int timeStepID, Message msg) {
		/*
		 * 1. SimulationID
		 * 2. ScenarioID
		 * 3. HostID (origanlly Sender)
		 * 4. HostID (originally target)
		 * 5. MessageID
		 * 6. TimestepID
		 * 
		 */
		Vector<String> tmp = new Vector<String>();
		tmp.add(host.getSimulationID() + "");
		tmp.add(host.getScenarioID() + "");
		tmp.add(host.getID() + "");
		tmp.add(target.getFirstPart());
		tmp.add(msg.getMsgID() + "");
		tmp.add(timeStepID + "");
		getInstance(host.getSimulationID()).informObserver(new MetricObject(MetricObjectType.ROUTING_MSG, tmp, "MessageLost", timeStepID, host.getDiscoveryMechanism()));			
	}

	public static void networkMsgSend(Host host, int timeStepID, Message msg,
			BluetoothDeviceAddress target) {
		/*
		 * 1. SimulationID
		 * 2. ScenarioID
		 * 3. HostID (Sender = source)
		 * 4. HostID (Receiver = target)
		 * 5. MessageID
		 * 6. TimestepID
		 * 
		 */
		Vector<String> tmp = new Vector<String>();
		tmp.add(host.getSimulationID() + "");
		tmp.add(host.getScenarioID() + "");
		tmp.add(host.getID() + "");
		tmp.add(target.getFirstPart());
		tmp.add(msg.getMsgID() + "");
		tmp.add(timeStepID + "");
		getInstance(host.getSimulationID()).informObserver(new MetricObject(MetricObjectType.ROUTING_MSG, tmp, "SendMessage", timeStepID, host.getDiscoveryMechanism()));			
		
	}

	public static void networkBecomeMaster(Host host, int timeStepID) {
		/*
		 * 1. SimulationID
		 * 2. ScenarioID
		 * 3. HostID 
		 * 4. TimestepID
		 * 
		 */
		Vector<String> tmp = new Vector<String>();
		tmp.add(host.getSimulationID() + "");
		tmp.add(host.getScenarioID() + "");
		tmp.add(host.getID() + "");
		tmp.add(timeStepID + "");
		getInstance(host.getSimulationID()).informObserver(new MetricObject(MetricObjectType.META_MSG, tmp, "HostBecomeMaster", timeStepID, host.getDiscoveryMechanism()));				
	}

	public static void networkBecomeSlave(Host host, int timeStepID) {
		/*
		 * 1. SimulationID
		 * 2. ScenarioID
		 * 3. HostID 
		 * 4. TimestepID
		 * 
		 */
		Vector<String> tmp = new Vector<String>();
		tmp.add(host.getSimulationID() + "");
		tmp.add(host.getScenarioID() + "");
		tmp.add(host.getID() + "");
		tmp.add(timeStepID + "");
		getInstance(host.getSimulationID()).informObserver(new MetricObject(MetricObjectType.META_MSG, tmp, "HostBecomeSlave", timeStepID, host.getDiscoveryMechanism()));				
	}

	public static void inquiryScan(Host host, int timeStepID) {
		/*
		 * 1. SimulationID
		 * 2. ScenarioID
		 * 3. HostID 
		 * 4. TimestepID
		 * 
		 */
		Vector<String> tmp = new Vector<String>();
		tmp.add(host.getSimulationID() + "");
		tmp.add(host.getScenarioID() + "");
		tmp.add(host.getID() + "");
		tmp.add(timeStepID + "");
		getInstance(host.getSimulationID()).informObserver(new MetricObject(MetricObjectType.META_MSG, tmp, "InquiryScanStarted", timeStepID, host.getDiscoveryMechanism()));					
	}

	public static void inquiryScanAnswer(Host host, int timeStepID) {
		/*
		 * 1. SimulationID
		 * 2. ScenarioID
		 * 3. HostID 
		 * 4. TimestepID
		 * 
		 */
		Vector<String> tmp = new Vector<String>();
		tmp.add(host.getSimulationID() + "");
		tmp.add(host.getScenarioID() + "");
		tmp.add(host.getID() + "");
		tmp.add(timeStepID + "");
		getInstance(host.getSimulationID()).informObserver(new MetricObject(MetricObjectType.META_MSG, tmp, "InquiryScanAnswer", timeStepID, host.getDiscoveryMechanism()));							
	}

	public static void simulationStepComplete(int simID, int scenID, int timeStepID) {
		/*
		 * 1. SimulationID
		 * 2. ScenarioID
		 * 3. TimestepID
		 * 
		 */
		Vector<String> tmp = new Vector<String>();
		tmp.add(simID + "");
		tmp.add(scenID + "");
		tmp.add(timeStepID + "");
		getInstance(simID).informObserver(new MetricObject(MetricObjectType.META_MSG, tmp, "SimulationStepComplete", timeStepID, null));							
	}

	public static void networkRfcommConnectReply(Host host, boolean success, int timeStepID) {
		/*
		 * 1. SimulationID
		 * 2. ScenarioID
		 * 3. HostID 
		 * 4. true or false
		 * 5. TimestepID
		 * 
		 */
		Vector<String> tmp = new Vector<String>();
		tmp.add(host.getSimulationID() + "");
		tmp.add(host.getScenarioID() + "");
		tmp.add(host.getID() + "");
		tmp.add(success + "");
		tmp.add(timeStepID + "");
		getInstance(host.getSimulationID()).informObserver(new MetricObject(MetricObjectType.ROUTING_MSG, tmp, "ConnectToServerResult", timeStepID, host.getDiscoveryMechanism()));							
	}

	public static void initialisationFinished(int simID, int scenID, int currentTime) {
		/*
		 * 1. SimulationID
		 * 2. ScenarioID
		 * 3. TimestepID
		 * 
		 */
		Vector<String> tmp = new Vector<String>();
		tmp.add(simID + "");
		tmp.add(scenID + "");
		tmp.add(currentTime + "");
		getInstance(simID).informObserver(new MetricObject(MetricObjectType.META_MSG, tmp, "InitialisationFinished", currentTime, null));							
		
	}

	public static void networkAnSingleConnectionEstablished(Host host1, Host host2, int timeStepID) {
		/*
		 * 1. SimulationID
		 * 2. ScenarioID
		 * 3. HostID 
		 * 4. true or false
		 * 5. TimestepID
		 * 
		 */
		Vector<String> tmp = new Vector<String>();
		tmp.add(host1.getSimulationID() + "");
		tmp.add(host1.getScenarioID() + "");
		tmp.add(host1.getID() + "");
		tmp.add(host2.getID() + "");
		tmp.add(timeStepID + "");
		getInstance(host1.getSimulationID()).informObserver(new MetricObject(MetricObjectType.META_MSG, tmp, "SingleConnectionsEstablished", timeStepID, host1.getDiscoveryMechanism()));							
	}
	
	public static void networkAnSingleConnectFailed(Host host1, Host host2, int timeStepID) {
		/*
		 * 1. SimulationID
		 * 2. ScenarioID
		 * 3. HostID 
		 * 4. true or false
		 * 5. TimestepID
		 * 
		 */
		Vector<String> tmp = new Vector<String>();
		tmp.add(host1.getSimulationID() + "");
		tmp.add(host1.getScenarioID() + "");
		tmp.add(host1.getID() + "");
		tmp.add(host2.getID() + "");
		tmp.add(timeStepID + "");
		getInstance(host1.getSimulationID()).informObserver(new MetricObject(MetricObjectType.META_MSG, tmp, "SingleConnectionFailed", timeStepID, host1.getDiscoveryMechanism()));							
	}
	
	public static void networkAnSingleConnectException(Host host1, Host host2, int timeStepID) {
		/*
		 * 1. SimulationID
		 * 2. ScenarioID
		 * 3. HostID 
		 * 4. true or false
		 * 5. TimestepID
		 * 
		 */
		Vector<String> tmp = new Vector<String>();
		tmp.add(host1.getSimulationID() + "");
		tmp.add(host1.getScenarioID() + "");
		tmp.add(host1.getID() + "");
		tmp.add(host2.getID() + "");
		tmp.add(timeStepID + "");
		getInstance(host1.getSimulationID()).informObserver(new MetricObject(MetricObjectType.META_MSG, tmp, "SingleConnectionException", timeStepID, host1.getDiscoveryMechanism()));							
	}

	public static void edgeRemoved(int simulation_ID, int id, String affectedEdge, int timeStepID) {
		/*
		 * 1. SimulationID
		 * 2. ScenarioID
		 * 3. EdgeID 
		 */
		Vector<String> tmp = new Vector<String>();
		tmp.add(simulation_ID + "");
		tmp.add(id + "");
		tmp.add(affectedEdge);
		getInstance(simulation_ID).informObserver(new MetricObject(MetricObjectType.META_MSG, tmp, "EdgeRemoved", timeStepID, null));							
	}
}
